#include "rsRecv_dirver.h"
#include <ctype.h>
#include <stdlib.h>

/**此为中断处理文件**/
/**
 * 作用接收上位机的控制信号，以及发生相关信息
 * 控制帧组成：开始(@)+读写(r/w)+控制码+参数+校验位+结束(\n)
 * 控制码及参数如下
 * __________________________________________
 * 功能         | 控制码 | 读写 | 参数 r：无参数                
 * ------------------------------------------
 * 频率         |   00  |   r/w |   E~19 运行时不可写
 * 占空比       |   01  |   r/w |   0~3E8 (对应占空比为0.0%~100.0%)
 * 电机最大速度 |   02  |   r/w |   0000~ffff
 * 电机启动     |   03  |   r/w |   0~1
 * 电机方向     |   04  |   r/w |   0~1
 * 编码器分辨率 |   05  |   r/w |   000~1f4
 * 减速比       |   06  |   r/w |   000~3e7
 * 电机实际速度 |   07  |   r   |
 * 分段速度1    |   08  |   r   |   
 * 分段速度2    |   09  |   r   |   
 * 分段速度3    |   0a  |   r   |  
 * 分段速度4    |   0b  |   r   |
 * 输入口电平   |   0c  |   r   |返回 00 01 10 11
 * pid使能      |   0d  |   r/w |   0~1
 * pid参数Kp    |   0e  |   r/w |   0~2710 
 * pid参数Ki    |   0f  |   r/w |   0~2710
 * pid参数Kd    |   10  |   r/w |   0~2710
 * pid目标值    |   11  |   r/w |   0000~ffff

校验位为crc-8,校验多项式为0x31 初始值0x00 输入反转:false 输出反转：false 结果异或0x00 例如： crc("01r1e7")的校验码为0xad,校验范围：读写(r/w)+控制码+参数

控制帧示例
设置电机占空比为50%即设置值为500->1f4:
@w011f49e\n
读取电机占空比：
@r01e5\n

**/
uint8_t RxBuff[1];      //进入中断接收数据的数组
uint8_t DataBuff[11]; //保存接收到的数据的数组
int RxLine=0;           //接收到的数据长度


/**********crc计算部分*****/
/**********开始************/
static uint8_t crc_table[] = {
    0x00,0x31,0x62,0x53,0xc4,0xf5,0xa6,0x97,0xb9,0x88,0xdb,0xea,0x7d,0x4c,0x1f,0x2e,
    0x43,0x72,0x21,0x10,0x87,0xb6,0xe5,0xd4,0xfa,0xcb,0x98,0xa9,0x3e,0x0f,0x5c,0x6d,
    0x86,0xb7,0xe4,0xd5,0x42,0x73,0x20,0x11,0x3f,0x0e,0x5d,0x6c,0xfb,0xca,0x99,0xa8,
    0xc5,0xf4,0xa7,0x96,0x01,0x30,0x63,0x52,0x7c,0x4d,0x1e,0x2f,0xb8,0x89,0xda,0xeb,
    0x3d,0x0c,0x5f,0x6e,0xf9,0xc8,0x9b,0xaa,0x84,0xb5,0xe6,0xd7,0x40,0x71,0x22,0x13,
    0x7e,0x4f,0x1c,0x2d,0xba,0x8b,0xd8,0xe9,0xc7,0xf6,0xa5,0x94,0x03,0x32,0x61,0x50,
    0xbb,0x8a,0xd9,0xe8,0x7f,0x4e,0x1d,0x2c,0x02,0x33,0x60,0x51,0xc6,0xf7,0xa4,0x95,
    0xf8,0xc9,0x9a,0xab,0x3c,0x0d,0x5e,0x6f,0x41,0x70,0x23,0x12,0x85,0xb4,0xe7,0xd6,
    0x7a,0x4b,0x18,0x29,0xbe,0x8f,0xdc,0xed,0xc3,0xf2,0xa1,0x90,0x07,0x36,0x65,0x54,
    0x39,0x08,0x5b,0x6a,0xfd,0xcc,0x9f,0xae,0x80,0xb1,0xe2,0xd3,0x44,0x75,0x26,0x17,
    0xfc,0xcd,0x9e,0xaf,0x38,0x09,0x5a,0x6b,0x45,0x74,0x27,0x16,0x81,0xb0,0xe3,0xd2,
    0xbf,0x8e,0xdd,0xec,0x7b,0x4a,0x19,0x28,0x06,0x37,0x64,0x55,0xc2,0xf3,0xa0,0x91,
    0x47,0x76,0x25,0x14,0x83,0xb2,0xe1,0xd0,0xfe,0xcf,0x9c,0xad,0x3a,0x0b,0x58,0x69,
    0x04,0x35,0x66,0x57,0xc0,0xf1,0xa2,0x93,0xbd,0x8c,0xdf,0xee,0x79,0x48,0x1b,0x2a,
    0xc1,0xf0,0xa3,0x92,0x05,0x34,0x67,0x56,0x78,0x49,0x1a,0x2b,0xbc,0x8d,0xde,0xef,
    0x82,0xb3,0xe0,0xd1,0x46,0x77,0x24,0x15,0x3b,0x0a,0x59,0x68,0xff,0xce,0x9d,0xac};

/*
 * uint8_t crc_8( const unsigned char *input_str, size_t num_bytes );
 *
 * The function crc_8() calculates the 8 bit wide CRC of an input string of a
 * given length.
 */
uint8_t crc_8(const unsigned char *ptr, size_t num_bytes)
{
    uint8_t crc = 0x00;
    if (ptr != NULL)
    {
        for (uint16_t a = 0; a < num_bytes; a++)
        {
            crc = crc_table[(*ptr) ^ crc];
            ptr++;
        }        
    }
    return crc;
} /* crc_8 */
/**********结束************/

/*判断是否是*/

/**帧处理**/
int cmd_process(const char* cmd, uint16_t len)
{
    //判断帧是否合法
    if(len < 7 || len > 11)
        return -1;
    if(cmd[1] != 'r' && cmd[1] != 'w' && cmd[1] != 'R' && cmd[1] != 'W')
        return -1;
    for(uint8_t i = 2; i < len-1; i ++)
    {
        if(isxdigit(cmd[i])==0)
            return -1;
    }
    //crc校验
    char data[11] = {0};
    char check[3] = {0};
    char *ptr;
    strncpy(data,cmd+1,len-4);
    //printf("data is %s\r\n",data);
    strncpy(check,cmd+(len-3),2);
    //printf("check is %s\r\n",check);
    if(crc_8((uint8_t *)data,strlen(data)) != strtol(check,&ptr,16))
        return -2;
    //printf("ok\r\n");
    char temp[8] = {0};
    if(data[0]=='w'||data[0]=='W')
    {
        strncpy(temp,data+1,2);
        uint8_t index = (uint8_t)strtol(temp,&ptr,16);
        memset(temp,0,sizeof(char)*8);
        strncpy(temp,data+3,strlen(data)-2);
        int number = strtol(temp,&ptr,16);
        switch(index)
        {
            case 0x00:
            {
                if(motor_get_runStatus() != 0)
                {
                    printf("!E03B\n");
                    break;
                }
                motor_set_freq(number); 
                printf("!ok9D\n");   
            }
            break;
            case 0x01:
            {
                if(number > 1000)
                {
                    printf("!E10A\n"); //参数错误
                    break;                    
                }
                motor_set_dutyCycle(number,motor_get_runDir());
                printf("!ok9D\n");
            } 
            break;

            case 0x02:
            {
                motor_set_maxSpeed(number);
                printf("!ok9D\n");
            } 
            break;
            case 0x03:
            {
                if(number != 1 && number != 0)
                {
                    printf("!E10A\n");
                    break;                    
                }
                motor_set_RunStatus(number);
                printf("!ok9D\n");
            } 
            break;
            case 0x04: //电机方向
            {
                if(number != 1 && number != 0)
                {
                    printf("!E10A\n");
                    break;                    
                }
                motor_set_RunDir(number);
                printf("!ok9D\n");
            } 
            break;
            case 0x05: //编码器分辨率
            {
                if(number > 0x1f4)
                {
                    printf("!E10A\n");
                    break;                    
                }
                motor_set_encoderResolution(number);
                printf("!ok9D\n");
            } 
            break;
            case 0x06: //减速比
            {
                if(number > 0x3e7)
                {
                    printf("!E10A\n");
                    break;                    
                }
                motor_set_reductionRatio(number);
                printf("!ok9D\n");
            } 
            break;
            case 0x0d: //pid使能
            {
                if(number != 1 && number != 0)
                {
                    printf("!E10A\n");
                    break;                    
                }
                motor_set_PIDenable(number);
                printf("!ok9D\n");
            } 
            break;
            case 0x0e: //pid kp
            {
                if(number > 0x2710)
                {
                    printf("!E10A\n");
                    break;                    
                }
                motor_set_pid_Kp((float)number/100.0);
                printf("!ok9D\n");
            } 
            break;

            case 0x0f: //pid ki
            {
                if(number > 0x2710)
                {
                    printf("!E10A\n");
                    break;                    
                }
                motor_set_pid_Ki((float)number/100.0);
                printf("!ok9D\n");
            } 
            break;
            case 0x10: //pid kd
            {
                if(number > 0x2710)
                {
                    printf("!E10A\n");
                    break;                    
                }
                motor_set_pid_Kd((float)number/100.0);
                printf("!ok9D\n");
            } 
            break;
            case 0x11:
            {
                if(motor_get_runDir() ==CCW)
                {
                    number = -number;
                }
                motor_set_pid_target(number);
                printf("!ok9D\n");               
            }
            break;
            default:
                printf("!E159\n");
            break;
        }
    }
    else if(data[0]=='r'||data[0]=='R')
    {
        strncpy(temp,data+1,2);
        uint8_t index = (uint8_t)strtol(temp,&ptr,16);
        memset(temp,0,sizeof(char)*8);
        switch(index)
        {
            case 0x00:
            sprintf(temp,"%X",motor_get_freq());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x01:
            sprintf(temp,"%X",motor_get_dutyCycle());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x02:
            sprintf(temp,"%X",motor_get_maxSpeed());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x03:
            sprintf(temp,"%X",motor_get_runStatus());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x04:
            sprintf(temp,"%X",motor_get_runDir());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x05:
            sprintf(temp,"%X",motor_get_encoderResolution());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x06:
            sprintf(temp,"%X",motor_get_reductionRatio());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x07:
            sprintf(temp,"%.2f",motor_get_speed());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x08:
            sprintf(temp,"%X",motor_get_io_speed1());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x09:
            sprintf(temp,"%X",motor_get_io_speed2());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x0a:
            sprintf(temp,"%X",motor_get_io_speed3());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x0b:
            sprintf(temp,"%X",motor_get_io_speed4());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x0c:
            sprintf(temp,"%2X",HAL_GPIO_ReadPin(INPUT1_EXTER_GPIO_Port,INPUT1_EXTER_Pin)<<1 | HAL_GPIO_ReadPin(INPUT2_GPIO_Port,INPUT2_Pin));
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x0d:
            sprintf(temp,"%X",motor_IsPIDenable());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x0e:
            sprintf(temp,"%.2f",motor_get_pid_Kp());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x0f:
            sprintf(temp,"%.2f",motor_get_pid_Ki());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x10:
            sprintf(temp,"%.2f",motor_get_pid_Kd());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;

            case 0x11:
            sprintf(temp,"%.2f",motor_get_pid_target());
            printf("!%s%2X",temp,crc_8((uint8_t *)temp,strlen(temp)));
            break;
            default:
                printf("!E159\n");
            break;
        }
    }
    else
    {
        return -1;
    }
    
    return 0;
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)
{
    static bool start_flag = false;
    if(motor_get_CtrlMode() == RS)
    {
        if(RxBuff[0] == '@')
            start_flag = true;
        
        if(start_flag)
        {
            RxLine++;
            if(RxLine > 11) //帧的长度超过范围直接退出
                goto GOTO_ERROR;
            DataBuff[RxLine-1] = RxBuff[0];
            if(RxBuff[0] == '\n')
            {
                printf("RXLen=%d\r\n",RxLine);
                printf("%s",DataBuff);
                cmd_process((char *)DataBuff,RxLine);
                GOTO_ERROR:
                memset(DataBuff,0,sizeof(char)*11);
                RxLine = 0;
                start_flag = false;
            }       
        }
        RxBuff[0] = 0;
        HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1);               
    }
}
